/**
 * @file exchange_main.cpp
 * @brief 交易所系统的主程序入口
 * 
 * @details 该文件实现了交易所系统的主程序，负责初始化和启动交易所的各个核心组件，
 * 包括匹配引擎、市场数据发布器和订单服务器。同时，它还处理外部信号，
 * 确保系统能够优雅地关闭。
 * 
 * @author 原作者
 * @date 2023
 */

#include <csignal>

#include "matcher/matching_engine.h"
#include "market_data/market_data_publisher.h"
#include "order_server/order_server.h"

/**
 * @brief 交易所系统的主要组件
 * 
 * @details 这些组件被声明为全局变量，以便信号处理函数能够访问并正确地关闭它们。
 * 包括日志记录器、匹配引擎、市场数据发布器和订单服务器。
 */
Common::Logger *logger = nullptr;                       ///< 日志记录器，用于记录系统日志
Exchange::MatchingEngine *matching_engine = nullptr;    ///< 匹配引擎，负责处理订单匹配
Exchange::MarketDataPublisher *market_data_publisher = nullptr;  ///< 市场数据发布器，负责发布市场数据
Exchange::OrderServer *order_server = nullptr;          ///< 订单服务器，负责处理客户端连接和订单请求

/**
 * @brief 处理外部信号，实现优雅关闭
 * 
 * @details 该函数在收到外部信号（如SIGINT）时被调用，负责安全地关闭交易所系统的所有组件。
 * 先等待10秒以确保当前操作完成，然后按顺序释放所有组件的资源，
 * 再等待10秒以确保资源释放完成，最后成功退出程序。
 * 
 * @param 信号编号（未使用）
 */
void signal_handler(int) {
  using namespace std::literals::chrono_literals;
  // 等待10秒以确保当前操作完成
  std::this_thread::sleep_for(10s);

  // 释放日志记录器资源
  delete logger;
  logger = nullptr;
  // 释放匹配引擎资源
  delete matching_engine;
  matching_engine = nullptr;
  // 释放市场数据发布器资源
  delete market_data_publisher;
  market_data_publisher = nullptr;
  // 释放订单服务器资源
  delete order_server;
  order_server = nullptr;

  // 再等待10秒以确保资源释放完成
  std::this_thread::sleep_for(10s);

  // 成功退出程序
  exit(EXIT_SUCCESS);
}

/**
 * @brief 交易所系统的主函数
 * 
 * @details 该函数是交易所系统的入口点，负责初始化和启动所有组件，包括：
 * 1. 初始化日志记录器
 * 2. 设置信号处理函数
 * 3. 创建各组件间通信的无锁队列
 * 4. 初始化并启动匹配引擎
 * 5. 初始化并启动市场数据发布器
 * 6. 初始化并启动订单服务器
 * 7. 进入主循环，保持系统运行
 * 
 * @param 命令行参数数量（未使用）
 * @param 命令行参数数组（未使用）
 * @return 程序退出码，正常情况下不会返回（主循环不退出）
 */
int main(int, char **) {
  // 初始化日志记录器
  logger = new Common::Logger("exchange_main.log");

  // 设置信号处理函数，处理SIGINT信号（如Ctrl+C）
  std::signal(SIGINT, signal_handler);

  // 设置主循环中的休眠时间（毫秒）
  const int sleep_time = 100 * 1000;

  /**
   * @brief 初始化组件间通信的无锁队列
   * 
   * @details 这些无锁队列用于各组件之间的高效通信：
   * - client_requests: 订单服务器 -> 匹配引擎，传递客户端请求
   * - client_responses: 匹配引擎 -> 订单服务器，传递客户端响应
   * - market_updates: 匹配引擎 -> 市场数据发布器，传递市场数据更新
   */
  Exchange::ClientRequestLFQueue client_requests(ME_MAX_CLIENT_UPDATES);   // 客户端请求队列
  Exchange::ClientResponseLFQueue client_responses(ME_MAX_CLIENT_UPDATES); // 客户端响应队列
  Exchange::MEMarketUpdateLFQueue market_updates(ME_MAX_MARKET_UPDATES);   // 市场数据更新队列

  // 用于日志记录的时间字符串缓冲区
  std::string time_str;

  // 记录匹配引擎启动日志
  logger->log("%:% %() % Starting Matching Engine...\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str));
  
  /**
   * @brief 初始化并启动匹配引擎
   * 
   * @details 创建匹配引擎实例，并将无锁队列传递给它，然后启动匹配引擎。
   * 匹配引擎负责处理客户端请求，生成客户端响应和市场数据更新。
   */
  matching_engine = new Exchange::MatchingEngine(&client_requests, &client_responses, &market_updates);
  matching_engine->start();

  /**
   * @brief 市场数据发布器的网络配置
   * 
   * @details 定义市场数据发布器的网络接口、IP地址和端口号。
   * 包括快照发布和增量发布两种模式的配置。
   */
  const std::string mkt_pub_iface = "lo";                                 // 网络接口，这里使用回环接口
  const std::string snap_pub_ip = "233.252.14.1", inc_pub_ip = "233.252.14.3";  // 快照和增量发布的多播地址
  const int snap_pub_port = 20000, inc_pub_port = 20001;                  // 快照和增量发布的端口号

  // 记录市场数据发布器启动日志
  logger->log("%:% %() % Starting Market Data Publisher...\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str));
  
  /**
   * @brief 初始化并启动市场数据发布器
   * 
   * @details 创建市场数据发布器实例，并将市场数据更新队列和网络配置传递给它，
   * 然后启动市场数据发布器。市场数据发布器负责将匹配引擎生成的市场数据更新
   * 通过网络发送给客户端，包括快照数据和增量数据。
   */
  market_data_publisher = new Exchange::MarketDataPublisher(&market_updates, mkt_pub_iface, snap_pub_ip, snap_pub_port, inc_pub_ip, inc_pub_port);
  market_data_publisher->start();

  /**
   * @brief 订单服务器的网络配置
   * 
   * @details 定义订单服务器的网络接口和端口号，用于监听客户端连接。
   */
  const std::string order_gw_iface = "lo";  // 网络接口，这里使用回环接口
  const int order_gw_port = 12345;         // 监听端口号

  // 记录订单服务器启动日志
  logger->log("%:% %() % Starting Order Server...\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str));
  
  /**
   * @brief 初始化并启动订单服务器
   * 
   * @details 创建订单服务器实例，并将客户端请求队列、客户端响应队列和网络配置传递给它，
   * 然后启动订单服务器。订单服务器负责接收客户端连接，处理客户端请求，
   * 并将匹配引擎的响应发送回客户端。
   */
  order_server = new Exchange::OrderServer(&client_requests, &client_responses, order_gw_iface, order_gw_port);
  order_server->start();

  // 记录系统初始化完成日志
  logger->log("%:% %() % System initialization complete. Running until signalled...\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str));

  /**
   * @brief 主程序循环
   * 
   * @details 进入无限循环，保持程序运行直到收到外部信号。
   * 在循环中，程序定期休眠一段时间，以减少CPU使用率。
   * 实际的处理工作在各个组件的独立线程中进行。
   */
  while (true) {
    // 休眠指定时间，减少CPU使用率
    std::this_thread::sleep_for(std::chrono::microseconds(sleep_time));
  }

  // 正常情况下不会执行到这里，因为程序将在信号处理函数中退出
  return 0;
}
